/*
**    Copyright (C) 2003-2011 Institute for Systems Biology
**                            Seattle, Washington, USA.
**
**    This library is free software; you can redistribute it and/or
**    modify it under the terms of the GNU Lesser General Public
**    License as published by the Free Software Foundation; either
**    version 3 of the License, or (at your option) any later version.
**
**    This library is distributed in the hope that it will be useful,
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
**    Lesser General Public License for more details.
**
**    You should have received a copy of the GNU Lesser General Public
**    License along with this library; if not, write to the Free Software
**    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*/

package org.systemsbiology.iteration;

import java.util.Iterator;

/**
 * An Iterator that takes a sequence of Iterator and iterates
 * over each Iterator in sequence, only failing a HasNext() check
 * once all Iterators are exhausted.
 * @author anorberg
 *
 * @param <E> Yield type of the iterators.
 */
public class CompoundIterator<E> implements Iterator<E> {

	private Iterator<? extends Iterator<? extends E>> root;
	private Iterator<? extends E> current; //Will never be null, by use of an EmptyIterator as a sentinel.
	
	public CompoundIterator(Iterator<? extends Iterator<? extends E>> root){
		this.root = root;
		current = new EmptyIterator<E>();
	}
	
	public CompoundIterator(Iterable<? extends Iterator<? extends E>> root){
		this(root.iterator());
	}
	
	/**
	 * Fixes up the state of the Iterators such that current.hasNext() == true if possible:
	 * <ul><li>Does nothing if this is already true.</li>
	 * <li>If this is false, finds the next iterator in root that hasNext().</li>
	 * <li>If root is exhausted, an exhausted iterator is retained in current, so hasNext will be false.</li>
	 * This will never leave a null in current.
	 */
	private void validate(){
		while(!current.hasNext()){
			if(root.hasNext()){
				current = root.next();
			} else {
				return; //iteration exhausted
			}
		}
	}
	
	@Override
	public boolean hasNext() {
		validate();
		return current.hasNext();
	}

	@Override
	public E next() {
		validate();
		return current.next();
	}

	@Override
	public void remove() {
		current.remove();
	}

}
